Load libraries
library(tidytext)
library(tidyverse)
library(quanteda)
library(lubridate)
library(ggplot2)
library(plotly)
library(forcats)
library(readxl)
library(leaflet)
library(leaflet.minicharts)
library(sp)
library(sf)
library(readr)
library(stringr)
library(rtweet)
library(ggraph)
library(ggrepel)
library(tidygraph)
Load Data
Parlamentarier <- read_csv("Data/Parlamentarier.csv")
[36m--[39m [1m[1mColumn specification[1m[22m [36m------------------------------------------------------------------------------------------------------------------------------[39m
cols(
.default = col_character(),
tags = [33mcol_logical()[39m,
Homepage_URL = [33mcol_logical()[39m,
SM_Twitter_id = [32mcol_double()[39m,
SM_Twitter_verifiziert = [33mcol_logical()[39m,
SM_Facebook_id = [32mcol_double()[39m,
SM_Facebook_verifiziert = [33mcol_logical()[39m,
SM_Youtube_user = [33mcol_logical()[39m,
SM_Youtube_id = [33mcol_logical()[39m,
SM_Youtube_verifiziert = [33mcol_logical()[39m,
SM_Instagram_user = [33mcol_logical()[39m,
SM_Instagram_id = [33mcol_logical()[39m,
SM_Instagram_verifiziert = [33mcol_logical()[39m,
SM_Telegram_user = [33mcol_logical()[39m,
SM_Telegram_id = [33mcol_logical()[39m,
SM_Telegram_verifiziert = [33mcol_logical()[39m,
created_at = [34mcol_datetime(format = "")[39m,
modified_at = [34mcol_datetime(format = "")[39m
)
[36mi[39m Use [38;5;251m[48;5;235m[38;5;251m[48;5;235m`spec()`[48;5;235m[38;5;251m[49m[39m for the full column specifications.
EU-Parlament rausfiltern
Parlamentarier <- Parlamentarier %>%
filter(Kategorie!="EU-Parlament")
Read Tabellen mit fehlenden Geschlechtern
alle_geschlechter <- read_excel("Data/Parlamentarier_geschechter.xlsx", sheet = "Geschlechter")
Join fehlende Geschlechterangaben
Parlamentarier <- Parlamentarier %>%
left_join(alle_geschlechter, by = c("Name" = "Name"))
Rename Spalten
Parlamentarier <- Parlamentarier %>%
rename(Geschlecht = Geschlecht.y)
Bundestag Geschlechterverteilung pro Partei
- filtern nach Bundestag
- CDU & CSU zusammenfügen
- nach männlich und weiblich gruppieren, Anzahl berechnen und sortieren
bundestag <- Parlamentarier %>%
select(id, Name, Geschlecht, Partei, Kategorie, SM_Twitter_id, SM_Twitter_user) %>%
filter(Kategorie=="Bundestag")
bundestag$Partei[bundestag$Partei == "CSU"] <-"CDU/CSU"
bundestag$Partei[bundestag$Partei=="CDU"]<-"CDU/CSU"
bundestag_man <- bundestag %>%
group_by(Partei) %>%
filter(Geschlecht == "männlich") %>%
summarise(gesamt_man=n())
bundestag_gesamt <- bundestag %>%
group_by(Partei) %>%
filter(Geschlecht == "weiblich") %>%
summarise(gesamt_frau=n()) %>%
left_join(bundestag_man) %>%
mutate(row_sum=rowSums(.[2:3])) %>%
arrange(desc(row_sum))
Joining, by = "Partei"
Barchart Bundestag
- Stacked-Barchart zur Geschlechterverteilung im Bundestag pro Partei
- visualisierung der Daten in möglichst geschlechterneuralen Farben
plot_ly(data=bundestag_gesamt, x=~reorder(Partei,-row_sum), y=~gesamt_frau, name="weiblich", marker=list(color=toRGB("#FB7F62")),
type="bar", hoverinfo="text", text=~paste("",row_sum),
hovertemplate=paste("Anzahl: %{y:,.0f}",
"<br>Gesamtanzahl: %{text}")) %>%
add_trace(y=~gesamt_man, name="männlich", marker=list(color=toRGB("#775285"))) %>%
layout(barmode="stack", title="Geschlechterverteilung in den Parteien im Bundestag", # titel position und größe ändern
xaxis = list(title = ""), yaxis=list(title="Anzahl Abgeordnete")) %>%
layout(legend=list(x=1, y=0.5))
Landtag Geschlechterverteilung pro Partei
- filtern allen Landtagen
- CDU & CSU sowie FDP & DVP zusammenfügen
- nach männlich und weiblich gruppieren, Anzahl berechnen und sortieren
landtag_partei <- Parlamentarier %>%
filter(Kategorie !="Bundestag") %>%
filter(Kategorie!="EU-Parlament") %>%
filter(Partei !="BIW") %>%
filter(Partei!="SSW") %>%
filter(Partei!="BVB/FW") %>%
filter(Partei!="FW")
landtag_partei$Partei[landtag_partei$Partei == "CSU"] <-"CDU/CSU"
landtag_partei$Partei[landtag_partei$Partei=="CDU"] <- "CDU/CSU"
landtag_partei$Partei[landtag_partei$Partei=="FDP/DVP"] <- "FDP"
landtag_man <- landtag_partei %>%
group_by(Partei) %>%
filter(Geschlecht=="männlich") %>%
summarise(gesamt_man=n())
landtag_gesamt <- landtag_partei %>%
group_by(Partei) %>%
filter(Geschlecht=="weiblich") %>%
summarise(gesamt_frau=n()) %>%
left_join(landtag_man) %>%
mutate(row_sum=rowSums(.[2:3])) %>%
arrange(desc(row_sum))
Joining, by = "Partei"
Barchart Landtag
- Stacked-Barchart zur Geschlechterverteilung in den Landtagen pro Partei
- visualisierung der Daten in möglichst geschlechterneuralen Farben
plot_ly(data=landtag_gesamt, x=~reorder(Partei,-row_sum), y=~gesamt_frau, name="weiblich", marker=list(color=toRGB("#FB7F62")),
type="bar", hoverinfo="text", text=~paste("",row_sum),
hovertemplate=paste("Anzahl: %{y:,.0f}",
"<br>Gesamtanzahl: %{text}")) %>%
add_trace(y=~gesamt_man, name="männlich", marker=list(color=toRGB("#775285"))) %>%
layout(barmode="stack", title="Geschlechterverteilung in den Parteien in den Landtagen", # titel position und größe ändern
xaxis=list(title=""), yaxis=list(title="Anzahl Abgeordnete")) %>%
layout(legend=list(x=1, y=0.5))
Map mit Geschlechterverteilung in den Landtagen
- Alle Landtage herausfiltern
parlamentarier_landtag <- Parlamentarier %>%
filter(Kategorie %in% c("Abgeordnetenhaus von Berlin",
"Bayerischer Landtag",
"Bremische Bürgerschaft",
"Hamburgische Bürgerschaft",
"Hessischer Landtag",
"Landtag Brandenburg",
"Landtag des Saarlandes",
"Landtag Mecklenburg-Vorpommern",
"Landtag Nordrhein-Westfalen",
"Landtag Rheinland-Pfalz",
"Landtag Sachsen-Anhalt",
"Landtag von Baden-Württemberg",
"Niedersächsischer Landtag",
"Sächsischer Landtag",
"Schleswig-Holsteinischer Landtag",
"Thüringer Landtag"))
- Vektoren und Dataframe erstellen mit den Koordinaten an denen die späteren Pie-Charts fixiert werden sollen. (Immer genau im Mittelpunkt des Bundeslandes)
Kategorie <- c("Abgeordnetenhaus von Berlin",
"Bayerischer Landtag",
"Bremische Bürgerschaft",
"Hamburgische Bürgerschaft",
"Hessischer Landtag",
"Landtag Brandenburg",
"Landtag des Saarlandes",
"Landtag Mecklenburg-Vorpommern",
"Landtag Nordrhein-Westfalen",
"Landtag Rheinland-Pfalz",
"Landtag Sachsen-Anhalt",
"Landtag von Baden-Württemberg",
"Niedersächsischer Landtag",
"Sächsischer Landtag",
"Schleswig-Holsteinischer Landtag",
"Thüringer Landtag")
lat <- c(52.520008,
48.917431,
53.074982,
53.553815,
50.652052,
52.408418,
49.396423,
53.612651,
51.433237,
50.118346,
51.950265,
48.661604,
52.636704,
51.104541,
54.219367,
51.010989)
lng <- c(13.404954,
11.407980,
8.807080,
9.991575,
9.162438,
12.562492,
7.022961,
12.429595,
7.661594,
7.308953,
11.692274,
9.350134,
9.845077,
13.201738,
9.696117,
10.845346)
bundeslaender_koordinaten <- data.frame(Kategorie, lat, lng)
- Dataframe nach Anzahl der männlichen und weiblichen Politiker*innen pro Bundesland filtern.
parlamentarier_man <- parlamentarier_landtag %>%
group_by(Kategorie) %>%
filter(Geschlecht == "männlich") %>%
summarise(männlich = n())
parlamentarier_landtag_gesamt <- parlamentarier_landtag %>%
group_by(Kategorie) %>%
filter(Geschlecht == "weiblich") %>%
summarise(weiblich = n()) %>%
left_join(parlamentarier_man)
Joining, by = "Kategorie"
- Koordinaten der späteren Pie-Charts zur Haupttabelle joinen
parlamentarier_koordinaten <- parlamentarier_landtag_gesamt %>%
left_join(bundeslaender_koordinaten, by = c("Kategorie" = "Kategorie"))
Map mit Pie-Charts
- geschlechterneutrale Farben für die Geschlechterverteilung erstellen, sowie die Grenzen der Bundesländer importieren und mit Namen versehen (popup).
colors <- c("#FB7F62", "#775285")
grenzen <- readRDS("Data/gadm36_DEU_1_sp.rds") %>%
st_as_sf()
popup_bundeslaender <- paste0("<strong>Bundesland: </strong>", grenzen$NAME_1)
- Pie-Charts mit Hilfe von addMinicharts zur Karte angefügt.
map <- leaflet() %>%
addProviderTiles(providers$CartoDB.VoyagerLabelsUnder) %>%
setView(lng = 10.451526, lat = 51.165691, zoom = 5.5) %>%
addPolygons(data = grenzen,
fillColor = "grey",
fillOpacity = 0.1,
weight = 3,
color = "grey",
popup = popup_bundeslaender) %>%
addMinicharts(
parlamentarier_koordinaten$lng, parlamentarier_koordinaten$lat,
type = "pie",
chartdata = parlamentarier_koordinaten[, c("weiblich", "männlich")],
colorPalette = colors,
width = 46,
height = 46,
opacity = 0.8,
legendPosition = "bottomright"
)
sf layer has inconsistent datum (+proj=longlat +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +no_defs).
Need '+proj=longlat +datum=WGS84'
map
Sentimentanalyse
- nach den “großen” Parteien filtern
- alle Politiker*innen entfernen, welche keinen Twitteraccount besitzen
- Usernames in Kleinschreibung formatieren
Parlamentarier_senti <- Parlamentarier %>%
filter(Partei!="BIW") %>%
filter(Partei!="SSW") %>%
filter(Partei!="BVB/FW") %>%
filter(Partei!="FW") %>%
filter(Partei!="fraktionslos") %>%
filter(SM_Twitter_user != "") %>%
select(Name, Partei, SM_Twitter_user, Geschlecht) %>%
mutate(SM_Twitter_user=tolower(SM_Twitter_user))
- CDU & CSU sowie FDP & DVP zusammenfügen
Parlamentarier_senti$Partei[Parlamentarier_senti$Partei == "CSU"] <- "CDU/CSU"
Parlamentarier_senti$Partei[Parlamentarier_senti$Partei == "CDU"] <- "CDU/CSU"
Parlamentarier_senti$Partei[Parlamentarier_senti$Partei == "FDP/DVP"] <- "FDP"
load("Data/sentiWS.RData")
sentiws <- dictionary(list(positive=positive, negative=negative))
- Corpus aus den Texten der gefilterten Tweets bilden
tweet_corpus <- corpus(filtert_tweets, text_field = "text")
- tokenisieren der Texte und bilden einer DFM
- sentiws und “Tweet-Tokens” zusammenführen, sowie nach screen_name gruppieren
token <- tokens(tweet_corpus)
dfm <- dfm(token)
senti <- dfm_lookup(dfm, sentiws)
senti <- dfm_group(senti, groups = screen_name)
- DFM zum Dataframe konvertieren
- doc_id in Kleinschreibung formatieren
- Parlamentarier_senti joinen
- Gruppieren nach Partei
- Sentiment der einzelnen User*innen auf Parteiebene zusammenfassen und Verhältnis positive/negative bilden
senti_frame <- senti %>%
convert(to= "data.frame") %>%
as_tibble() %>%
mutate(doc_id=tolower(doc_id))
Fehler in UseMethod("convert") :
nicht anwendbare Methode für 'convert' auf Objekt der Klasse "c('dfm', 'dgCMatrix', 'CsparseMatrix', 'dsparseMatrix', 'generalMatrix', 'dCsparseMatrix', 'dMatrix', 'sparseMatrix', 'compMatrix', 'Matrix', 'xMatrix', 'mMatrix', 'Mnumeric', 'replValueSp')" angewendet
Barchart
- Partei absteigend nach negativem Sentiment sortieren
- Beschriftung der X- und Y Werte ändern
- Barchart bilden und in ggplotly konvertieren
senti_bar <- senti_final_frame %>%
mutate(Partei = fct_reorder(Partei, positive, max)) %>%
pivot_longer(c(positive, negative), values_to = c("Verhältnis"), names_to = c("Äußerung")) %>%
ggplot() +
geom_bar(aes(Partei,
Verhältnis,
fill = Äußerung),
position = "stack",
stat = "identity") +
scale_fill_manual(values = c("#f46666", "#8EC9BB")) +
theme_classic() +
labs(
title = "Äußerungen der Politiker*innen auf Twitter zum Thema 'Gender'",
subtitle = "Einschätzung durch Sentimentanalyse",
x = "Partei",
y = "Verhältnis",
fill = "Äußerung"
)
final_senti_plot <- ggplotly(senti_bar)
final_senti_plot
Netzwerk
Zuweisung von Attributen an Nodes: * Parteizugehörigkeit in Farbe * Klarname der Politikerinnen als Label Anzahl der Tweets in Größe
netz_plot <- netz %>%
filter(component <= 6) %>%
mutate(degree = centrality_degree(mode = "in")) %>%
ggraph(layout = "fr") +
geom_edge_link(alpha = 0.25, arrow = arrow(length = unit("5", "mm"))) +
geom_node_point(aes(size = n, color = Partei)) +
scale_color_manual(values = partei_farben) +
theme_graph(background = "white") + # theme
geom_node_label(aes(filter = n >= 15, label = Name), repel = T, show.legend = F, alpha = 0.5) + #position = "jitter"
labs(title = "Retweet-Netzwerke deutscher Politiker*innen", size = "Anzahl Tweets", subtitle = "zum Thema 'Gender' ab 2016")
netz_plot

NODES DEUTLICHERE ABSTUFUNG, VLT. THEME FUNKTIONIERT NICHT RICHTIG
LS0tDQp0aXRsZTogIlJfUHJvamVrdF9HZW5kZXIiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KIyBMb2FkIGxpYnJhcmllcyANCg0KYGBge3J9DQpsaWJyYXJ5KHRpZHl0ZXh0KQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHF1YW50ZWRhKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoZm9yY2F0cykNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeShsZWFmbGV0Lm1pbmljaGFydHMpDQpsaWJyYXJ5KHNwKQ0KbGlicmFyeShzZikNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KHN0cmluZ3IpDQpsaWJyYXJ5KHJ0d2VldCkNCmxpYnJhcnkoZ2dyYXBoKQ0KbGlicmFyeShnZ3JlcGVsKQ0KbGlicmFyeSh0aWR5Z3JhcGgpDQpgYGANCg0KIyBMb2FkIERhdGEgDQoNCmBgYHtyfQ0KUGFybGFtZW50YXJpZXIgPC0gcmVhZF9jc3YoIkRhdGEvUGFybGFtZW50YXJpZXIuY3N2IikNCmBgYA0KDQpFVS1QYXJsYW1lbnQgcmF1c2ZpbHRlcm4NCmBgYHtyfQ0KUGFybGFtZW50YXJpZXIgPC0gUGFybGFtZW50YXJpZXIgJT4lIA0KICBmaWx0ZXIoS2F0ZWdvcmllIT0iRVUtUGFybGFtZW50IikNCmBgYA0KDQpSZWFkIFRhYmVsbGVuIG1pdCBmZWhsZW5kZW4gR2VzY2hsZWNodGVybg0KYGBge3J9DQphbGxlX2dlc2NobGVjaHRlciA8LSByZWFkX2V4Y2VsKCJEYXRhL1BhcmxhbWVudGFyaWVyX2dlc2NoZWNodGVyLnhsc3giLCBzaGVldCA9ICJHZXNjaGxlY2h0ZXIiKQ0KYGBgDQoNCkpvaW4gZmVobGVuZGUgR2VzY2hsZWNodGVyYW5nYWJlbiANCmBgYHtyfQ0KUGFybGFtZW50YXJpZXIgPC0gUGFybGFtZW50YXJpZXIgJT4lIA0KICBsZWZ0X2pvaW4oYWxsZV9nZXNjaGxlY2h0ZXIsIGJ5ID0gYygiTmFtZSIgPSAiTmFtZSIpKQ0KYGBgDQoNClJlbmFtZSBTcGFsdGVuDQpgYGB7cn0NClBhcmxhbWVudGFyaWVyIDwtIFBhcmxhbWVudGFyaWVyICU+JSANCiAgcmVuYW1lKEdlc2NobGVjaHQgPSBHZXNjaGxlY2h0LnkpDQpgYGANCg0KIyBCdW5kZXN0YWcgR2VzY2hsZWNodGVydmVydGVpbHVuZyBwcm8gUGFydGVpDQoNCiogZmlsdGVybiBuYWNoIEJ1bmRlc3RhZw0KKiBDRFUgJiBDU1UgenVzYW1tZW5mw7xnZW4gDQoqIG5hY2ggbcOkbm5saWNoIHVuZCB3ZWlibGljaCBncnVwcGllcmVuLCBBbnphaGwgYmVyZWNobmVuIHVuZCBzb3J0aWVyZW4NCmBgYHtyfQ0KYnVuZGVzdGFnIDwtIFBhcmxhbWVudGFyaWVyICU+JSANCiAgc2VsZWN0KGlkLCBOYW1lLCBHZXNjaGxlY2h0LCBQYXJ0ZWksIEthdGVnb3JpZSwgU01fVHdpdHRlcl9pZCwgU01fVHdpdHRlcl91c2VyKSAlPiUgDQogIGZpbHRlcihLYXRlZ29yaWU9PSJCdW5kZXN0YWciKQ0KDQpidW5kZXN0YWckUGFydGVpW2J1bmRlc3RhZyRQYXJ0ZWkgPT0gIkNTVSJdIDwtIkNEVS9DU1UiDQpidW5kZXN0YWckUGFydGVpW2J1bmRlc3RhZyRQYXJ0ZWk9PSJDRFUiXTwtIkNEVS9DU1UiDQoNCmJ1bmRlc3RhZ19tYW4gPC0gYnVuZGVzdGFnICU+JSANCiAgZ3JvdXBfYnkoUGFydGVpKSAlPiUgDQogIGZpbHRlcihHZXNjaGxlY2h0ID09ICJtw6RubmxpY2giKSAlPiUgDQogIHN1bW1hcmlzZShnZXNhbXRfbWFuPW4oKSkNCg0KYnVuZGVzdGFnX2dlc2FtdCA8LSBidW5kZXN0YWcgJT4lIA0KICBncm91cF9ieShQYXJ0ZWkpICU+JSANCiAgZmlsdGVyKEdlc2NobGVjaHQgPT0gIndlaWJsaWNoIikgJT4lIA0KICBzdW1tYXJpc2UoZ2VzYW10X2ZyYXU9bigpKSAlPiUgDQogIGxlZnRfam9pbihidW5kZXN0YWdfbWFuKSAlPiUgDQogIG11dGF0ZShyb3dfc3VtPXJvd1N1bXMoLlsyOjNdKSkgJT4lIA0KICBhcnJhbmdlKGRlc2Mocm93X3N1bSkpDQpgYGANCg0KIyMjIEJhcmNoYXJ0IEJ1bmRlc3RhZw0KDQoqIFN0YWNrZWQtQmFyY2hhcnQgenVyIEdlc2NobGVjaHRlcnZlcnRlaWx1bmcgaW0gQnVuZGVzdGFnIHBybyBQYXJ0ZWkNCiogdmlzdWFsaXNpZXJ1bmcgZGVyIERhdGVuIGluIG3DtmdsaWNoc3QgZ2VzY2hsZWNodGVybmV1cmFsZW4gRmFyYmVuDQpgYGB7cn0NCnBsb3RfbHkoZGF0YT1idW5kZXN0YWdfZ2VzYW10LCB4PX5yZW9yZGVyKFBhcnRlaSwtcm93X3N1bSksIHk9fmdlc2FtdF9mcmF1LCBuYW1lPSJ3ZWlibGljaCIsIG1hcmtlcj1saXN0KGNvbG9yPXRvUkdCKCIjRkI3RjYyIikpLA0KICAgICAgICB0eXBlPSJiYXIiLCBob3ZlcmluZm89InRleHQiLCB0ZXh0PX5wYXN0ZSgiIixyb3dfc3VtKSwgDQogICAgICAgIGhvdmVydGVtcGxhdGU9cGFzdGUoIkFuemFobDogJXt5OiwuMGZ9IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxicj5HZXNhbXRhbnphaGw6ICV7dGV4dH0iKSkgJT4lIA0KICBhZGRfdHJhY2UoeT1+Z2VzYW10X21hbiwgbmFtZT0ibcOkbm5saWNoIiwgbWFya2VyPWxpc3QoY29sb3I9dG9SR0IoIiM3NzUyODUiKSkpICU+JSANCiAgbGF5b3V0KGJhcm1vZGU9InN0YWNrIiwgdGl0bGU9Ikdlc2NobGVjaHRlcnZlcnRlaWx1bmcgaW4gZGVuIFBhcnRlaWVuIGltIEJ1bmRlc3RhZyIsICMgdGl0ZWwgcG9zaXRpb24gdW5kIGdyw7bDn2Ugw6RuZGVybg0KICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIiIpLCB5YXhpcz1saXN0KHRpdGxlPSJBbnphaGwgQWJnZW9yZG5ldGUiKSkgJT4lDQogIGxheW91dChsZWdlbmQ9bGlzdCh4PTEsIHk9MC41KSkNCmBgYA0KDQojIExhbmR0YWcgR2VzY2hsZWNodGVydmVydGVpbHVuZyBwcm8gUGFydGVpDQoNCiogZmlsdGVybiBhbGxlbiBMYW5kdGFnZW4NCiogQ0RVICYgQ1NVIHNvd2llIEZEUCAmIERWUCB6dXNhbW1lbmbDvGdlbiANCiogbmFjaCBtw6RubmxpY2ggdW5kIHdlaWJsaWNoIGdydXBwaWVyZW4sIEFuemFobCBiZXJlY2huZW4gdW5kIHNvcnRpZXJlbg0KYGBge3J9DQpsYW5kdGFnX3BhcnRlaSA8LSBQYXJsYW1lbnRhcmllciAlPiUgDQogIGZpbHRlcihLYXRlZ29yaWUgIT0iQnVuZGVzdGFnIikgJT4lIA0KICBmaWx0ZXIoS2F0ZWdvcmllIT0iRVUtUGFybGFtZW50IikgJT4lIA0KICBmaWx0ZXIoUGFydGVpICE9IkJJVyIpICU+JSANCiAgZmlsdGVyKFBhcnRlaSE9IlNTVyIpICU+JSANCiAgZmlsdGVyKFBhcnRlaSE9IkJWQi9GVyIpICU+JSANCiAgZmlsdGVyKFBhcnRlaSE9IkZXIikNCmBgYA0KDQpgYGB7cn0NCmxhbmR0YWdfcGFydGVpJFBhcnRlaVtsYW5kdGFnX3BhcnRlaSRQYXJ0ZWkgPT0gIkNTVSJdIDwtIkNEVS9DU1UiDQpsYW5kdGFnX3BhcnRlaSRQYXJ0ZWlbbGFuZHRhZ19wYXJ0ZWkkUGFydGVpPT0iQ0RVIl0gPC0gIkNEVS9DU1UiDQpsYW5kdGFnX3BhcnRlaSRQYXJ0ZWlbbGFuZHRhZ19wYXJ0ZWkkUGFydGVpPT0iRkRQL0RWUCJdIDwtICJGRFAiIA0KYGBgDQoNCmBgYHtyfQ0KbGFuZHRhZ19tYW4gPC0gbGFuZHRhZ19wYXJ0ZWkgJT4lIA0KICBncm91cF9ieShQYXJ0ZWkpICU+JSANCiAgZmlsdGVyKEdlc2NobGVjaHQ9PSJtw6RubmxpY2giKSAlPiUgDQogIHN1bW1hcmlzZShnZXNhbXRfbWFuPW4oKSkNCg0KbGFuZHRhZ19nZXNhbXQgPC0gbGFuZHRhZ19wYXJ0ZWkgJT4lIA0KICBncm91cF9ieShQYXJ0ZWkpICU+JSANCiAgZmlsdGVyKEdlc2NobGVjaHQ9PSJ3ZWlibGljaCIpICU+JSANCiAgc3VtbWFyaXNlKGdlc2FtdF9mcmF1PW4oKSkgJT4lIA0KICBsZWZ0X2pvaW4obGFuZHRhZ19tYW4pICU+JSANCiAgIG11dGF0ZShyb3dfc3VtPXJvd1N1bXMoLlsyOjNdKSkgJT4lIA0KICBhcnJhbmdlKGRlc2Mocm93X3N1bSkpDQpgYGANCg0KIyMjIEJhcmNoYXJ0IExhbmR0YWcNCg0KKiBTdGFja2VkLUJhcmNoYXJ0IHp1ciBHZXNjaGxlY2h0ZXJ2ZXJ0ZWlsdW5nIGluIGRlbiBMYW5kdGFnZW4gcHJvIFBhcnRlaQ0KKiB2aXN1YWxpc2llcnVuZyBkZXIgRGF0ZW4gaW4gbcO2Z2xpY2hzdCBnZXNjaGxlY2h0ZXJuZXVyYWxlbiBGYXJiZW4NCmBgYHtyfQ0KcGxvdF9seShkYXRhPWxhbmR0YWdfZ2VzYW10LCB4PX5yZW9yZGVyKFBhcnRlaSwtcm93X3N1bSksIHk9fmdlc2FtdF9mcmF1LCBuYW1lPSJ3ZWlibGljaCIsIG1hcmtlcj1saXN0KGNvbG9yPXRvUkdCKCIjRkI3RjYyIikpLCANCiAgICAgICAgdHlwZT0iYmFyIiwgaG92ZXJpbmZvPSJ0ZXh0IiwgdGV4dD1+cGFzdGUoIiIscm93X3N1bSksIA0KICAgICAgICBob3ZlcnRlbXBsYXRlPXBhc3RlKCJBbnphaGw6ICV7eTosLjBmfSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8YnI+R2VzYW10YW56YWhsOiAle3RleHR9IikpICU+JSANCiAgYWRkX3RyYWNlKHk9fmdlc2FtdF9tYW4sIG5hbWU9Im3DpG5ubGljaCIsIG1hcmtlcj1saXN0KGNvbG9yPXRvUkdCKCIjNzc1Mjg1IikpKSAlPiUgDQogIGxheW91dChiYXJtb2RlPSJzdGFjayIsIHRpdGxlPSJHZXNjaGxlY2h0ZXJ2ZXJ0ZWlsdW5nIGluIGRlbiBQYXJ0ZWllbiBpbiBkZW4gTGFuZHRhZ2VuIiwgIyB0aXRlbCBwb3NpdGlvbiB1bmQgZ3LDtsOfZSDDpG5kZXJuDQogICAgICAgICB4YXhpcz1saXN0KHRpdGxlPSIiKSwgeWF4aXM9bGlzdCh0aXRsZT0iQW56YWhsIEFiZ2VvcmRuZXRlIikpICU+JQ0KICBsYXlvdXQobGVnZW5kPWxpc3QoeD0xLCB5PTAuNSkpDQpgYGANCg0KIyBNYXAgbWl0IEdlc2NobGVjaHRlcnZlcnRlaWx1bmcgaW4gZGVuIExhbmR0YWdlbg0KDQoqIEFsbGUgTGFuZHRhZ2UgaGVyYXVzZmlsdGVybg0KYGBge3J9DQpwYXJsYW1lbnRhcmllcl9sYW5kdGFnIDwtIFBhcmxhbWVudGFyaWVyICU+JSANCiAgZmlsdGVyKEthdGVnb3JpZSAlaW4lIGMoIkFiZ2VvcmRuZXRlbmhhdXMgdm9uIEJlcmxpbiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiQmF5ZXJpc2NoZXIgTGFuZHRhZyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiQnJlbWlzY2hlIELDvHJnZXJzY2hhZnQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIkhhbWJ1cmdpc2NoZSBCw7xyZ2Vyc2NoYWZ0IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJIZXNzaXNjaGVyIExhbmR0YWciLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIkxhbmR0YWcgQnJhbmRlbmJ1cmciLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIkxhbmR0YWcgZGVzIFNhYXJsYW5kZXMiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIkxhbmR0YWcgTWVja2xlbmJ1cmctVm9ycG9tbWVybiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiTGFuZHRhZyBOb3JkcmhlaW4tV2VzdGZhbGVuIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJMYW5kdGFnIFJoZWlubGFuZC1QZmFseiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiTGFuZHRhZyBTYWNoc2VuLUFuaGFsdCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiTGFuZHRhZyB2b24gQmFkZW4tV8O8cnR0ZW1iZXJnIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJOaWVkZXJzw6RjaHNpc2NoZXIgTGFuZHRhZyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiU8OkY2hzaXNjaGVyIExhbmR0YWciLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIlNjaGxlc3dpZy1Ib2xzdGVpbmlzY2hlciBMYW5kdGFnIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJUaMO8cmluZ2VyIExhbmR0YWciKSkNCmBgYA0KDQoqIFZla3RvcmVuIHVuZCBEYXRhZnJhbWUgZXJzdGVsbGVuIG1pdCBkZW4gS29vcmRpbmF0ZW4gYW4gZGVuZW4gZGllIHNww6R0ZXJlbiBQaWUtQ2hhcnRzIGZpeGllcnQgd2VyZGVuIHNvbGxlbi4gKEltbWVyIGdlbmF1IGltIE1pdHRlbHB1bmt0IGRlcyBCdW5kZXNsYW5kZXMpDQoNCmBgYHtyfQ0KS2F0ZWdvcmllIDwtIGMoIkFiZ2VvcmRuZXRlbmhhdXMgdm9uIEJlcmxpbiIsIA0KICAgICAgICAgICAgICAgIkJheWVyaXNjaGVyIExhbmR0YWciLCANCiAgICAgICAgICAgICAgICJCcmVtaXNjaGUgQsO8cmdlcnNjaGFmdCIsDQogICAgICAgICAgICAgICAiSGFtYnVyZ2lzY2hlIELDvHJnZXJzY2hhZnQiLCANCiAgICAgICAgICAgICAgICJIZXNzaXNjaGVyIExhbmR0YWciLA0KICAgICAgICAgICAgICAgIkxhbmR0YWcgQnJhbmRlbmJ1cmciLCANCiAgICAgICAgICAgICAgICJMYW5kdGFnIGRlcyBTYWFybGFuZGVzIiwNCiAgICAgICAgICAgICAgICJMYW5kdGFnIE1lY2tsZW5idXJnLVZvcnBvbW1lcm4iLA0KICAgICAgICAgICAgICAgIkxhbmR0YWcgTm9yZHJoZWluLVdlc3RmYWxlbiIsDQogICAgICAgICAgICAgICAiTGFuZHRhZyBSaGVpbmxhbmQtUGZhbHoiLA0KICAgICAgICAgICAgICAgIkxhbmR0YWcgU2FjaHNlbi1BbmhhbHQiLCANCiAgICAgICAgICAgICAgICJMYW5kdGFnIHZvbiBCYWRlbi1Xw7xydHRlbWJlcmciLCANCiAgICAgICAgICAgICAgICJOaWVkZXJzw6RjaHNpc2NoZXIgTGFuZHRhZyIsIA0KICAgICAgICAgICAgICAgIlPDpGNoc2lzY2hlciBMYW5kdGFnIiwgDQogICAgICAgICAgICAgICAiU2NobGVzd2lnLUhvbHN0ZWluaXNjaGVyIExhbmR0YWciLCANCiAgICAgICAgICAgICAgICJUaMO8cmluZ2VyIExhbmR0YWciKQ0KDQpsYXQgPC0gYyg1Mi41MjAwMDgsDQogICAgICAgICA0OC45MTc0MzEsDQogICAgICAgICA1My4wNzQ5ODIsDQogICAgICAgICA1My41NTM4MTUsDQogICAgICAgICA1MC42NTIwNTIsDQogICAgICAgICA1Mi40MDg0MTgsDQogICAgICAgICA0OS4zOTY0MjMsDQogICAgICAgICA1My42MTI2NTEsDQogICAgICAgICA1MS40MzMyMzcsDQogICAgICAgICA1MC4xMTgzNDYsDQogICAgICAgICA1MS45NTAyNjUsDQogICAgICAgICA0OC42NjE2MDQsDQogICAgICAgICA1Mi42MzY3MDQsDQogICAgICAgICA1MS4xMDQ1NDEsDQogICAgICAgICA1NC4yMTkzNjcsDQogICAgICAgICA1MS4wMTA5ODkpDQoNCmxuZyA8LSBjKDEzLjQwNDk1NCwNCiAgICAgICAgIDExLjQwNzk4MCwNCiAgICAgICAgIDguODA3MDgwLA0KICAgICAgICAgOS45OTE1NzUsDQogICAgICAgICA5LjE2MjQzOCwNCiAgICAgICAgIDEyLjU2MjQ5MiwNCiAgICAgICAgIDcuMDIyOTYxLA0KICAgICAgICAgMTIuNDI5NTk1LA0KICAgICAgICAgNy42NjE1OTQsDQogICAgICAgICA3LjMwODk1MywNCiAgICAgICAgIDExLjY5MjI3NCwNCiAgICAgICAgIDkuMzUwMTM0LA0KICAgICAgICAgOS44NDUwNzcsDQogICAgICAgICAxMy4yMDE3MzgsDQogICAgICAgICA5LjY5NjExNywNCiAgICAgICAgIDEwLjg0NTM0NikNCg0KYnVuZGVzbGFlbmRlcl9rb29yZGluYXRlbiA8LSBkYXRhLmZyYW1lKEthdGVnb3JpZSwgbGF0LCBsbmcpDQpgYGANCg0KKiBEYXRhZnJhbWUgbmFjaCBBbnphaGwgZGVyIG3DpG5ubGljaGVuIHVuZCB3ZWlibGljaGVuIFBvbGl0aWtlcippbm5lbiBwcm8gQnVuZGVzbGFuZCBmaWx0ZXJuLg0KDQpgYGB7cn0NCnBhcmxhbWVudGFyaWVyX21hbiA8LSBwYXJsYW1lbnRhcmllcl9sYW5kdGFnICU+JSANCiAgZ3JvdXBfYnkoS2F0ZWdvcmllKSAlPiUgDQogIGZpbHRlcihHZXNjaGxlY2h0ID09ICJtw6RubmxpY2giKSAlPiUgDQogIHN1bW1hcmlzZShtw6RubmxpY2ggPSBuKCkpDQoNCnBhcmxhbWVudGFyaWVyX2xhbmR0YWdfZ2VzYW10IDwtIHBhcmxhbWVudGFyaWVyX2xhbmR0YWcgJT4lIA0KICBncm91cF9ieShLYXRlZ29yaWUpICU+JSANCiAgZmlsdGVyKEdlc2NobGVjaHQgPT0gIndlaWJsaWNoIikgJT4lIA0KICBzdW1tYXJpc2Uod2VpYmxpY2ggPSBuKCkpICU+JSANCiAgbGVmdF9qb2luKHBhcmxhbWVudGFyaWVyX21hbikNCmBgYA0KDQoqIEtvb3JkaW5hdGVuIGRlciBzcMOkdGVyZW4gUGllLUNoYXJ0cyB6dXIgSGF1cHR0YWJlbGxlIGpvaW5lbg0KDQpgYGB7cn0NCnBhcmxhbWVudGFyaWVyX2tvb3JkaW5hdGVuIDwtIHBhcmxhbWVudGFyaWVyX2xhbmR0YWdfZ2VzYW10ICU+JSANCiAgbGVmdF9qb2luKGJ1bmRlc2xhZW5kZXJfa29vcmRpbmF0ZW4sIGJ5ID0gYygiS2F0ZWdvcmllIiA9ICJLYXRlZ29yaWUiKSkNCmBgYA0KDQojIE1hcCBtaXQgUGllLUNoYXJ0cw0KDQoqIGdlc2NobGVjaHRlcm5ldXRyYWxlIEZhcmJlbiBmw7xyIGRpZSBHZXNjaGxlY2h0ZXJ2ZXJ0ZWlsdW5nIGVyc3RlbGxlbiwgc293aWUgZGllIEdyZW56ZW4gZGVyIEJ1bmRlc2zDpG5kZXIgaW1wb3J0aWVyZW4gdW5kIG1pdCBOYW1lbiB2ZXJzZWhlbiAocG9wdXApLg0KYGBge3J9DQpjb2xvcnMgPC0gYygiI0ZCN0Y2MiIsICIjNzc1Mjg1IikNCg0KZ3JlbnplbiA8LSByZWFkUkRTKCJEYXRhL2dhZG0zNl9ERVVfMV9zcC5yZHMiKSAlPiUgDQogIHN0X2FzX3NmKCkNCg0KcG9wdXBfYnVuZGVzbGFlbmRlciA8LSBwYXN0ZTAoIjxzdHJvbmc+QnVuZGVzbGFuZDogPC9zdHJvbmc+IiwgZ3JlbnplbiROQU1FXzEpDQpgYGANCg0KKiBQaWUtQ2hhcnRzIG1pdCBIaWxmZSB2b24gYWRkTWluaWNoYXJ0cyB6dXIgS2FydGUgYW5nZWbDvGd0LiANCg0KYGBge3J9DQptYXAgPC0gbGVhZmxldCgpICU+JSANCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Wb3lhZ2VyTGFiZWxzVW5kZXIpICU+JSANCiAgc2V0VmlldyhsbmcgPSAxMC40NTE1MjYsIGxhdCA9IDUxLjE2NTY5MSwgem9vbSA9IDUuNSkgJT4lIA0KICBhZGRQb2x5Z29ucyhkYXRhID0gZ3JlbnplbiwNCiAgICAgICAgICAgICAgZmlsbENvbG9yID0gImdyZXkiLA0KICAgICAgICAgICAgICBmaWxsT3BhY2l0eSA9IDAuMSwNCiAgICAgICAgICAgICAgd2VpZ2h0ID0gMywNCiAgICAgICAgICAgICAgY29sb3IgPSAiZ3JleSIsDQogICAgICAgICAgICAgIHBvcHVwID0gcG9wdXBfYnVuZGVzbGFlbmRlcikgJT4lIA0KICBhZGRNaW5pY2hhcnRzKA0KICAgIHBhcmxhbWVudGFyaWVyX2tvb3JkaW5hdGVuJGxuZywgcGFybGFtZW50YXJpZXJfa29vcmRpbmF0ZW4kbGF0LA0KICAgIHR5cGUgPSAicGllIiwNCiAgICBjaGFydGRhdGEgPSBwYXJsYW1lbnRhcmllcl9rb29yZGluYXRlblssIGMoIndlaWJsaWNoIiwgIm3DpG5ubGljaCIpXSwNCiAgICBjb2xvclBhbGV0dGUgPSBjb2xvcnMsDQogICAgd2lkdGggPSA0NiwNCiAgICBoZWlnaHQgPSA0NiwNCiAgICBvcGFjaXR5ID0gMC44LA0KICAgIGxlZ2VuZFBvc2l0aW9uID0gImJvdHRvbXJpZ2h0Ig0KICApDQptYXANCmBgYA0KDQojIFR3ZWV0cyBkZXIgUG9saXRpa2VyKmlubmVuIHNjcmFwZW4NCg0KTmljaHQgYWxzIGF1c2bDvGhyYmFyZW4gQ29kZSwgZGFtaXQgZGllIERhdGVuIG5pY2h0IG5vY2htYWxzIGdlem9nZW4gd2VyZGVuLi4uDQoNClR3aXR0ZXJfYWNjb3VudHMgPC0gUGFybGFtZW50YXJpZXIgJT4lDQogIGZpbHRlcihLYXRlZ29yaWUhPSJFVS1QYXJsYW1lbnQiKSAlPiUNCiAgZmlsdGVyKFBhcnRlaSE9IkJJVyIpICU+JSANCiAgZmlsdGVyKFBhcnRlaSE9IlNTVyIpICU+JSANCiAgZmlsdGVyKFBhcnRlaSE9IkJWQi9GVyIpICU+JSANCiAgZmlsdGVyKFBhcnRlaSE9IkZXIikgJT4lIA0KICBmaWx0ZXIoUGFydGVpIT0iZnJha3Rpb25zbG9zIikgJT4lIA0KICBmaWx0ZXIoU01fVHdpdHRlcl91c2VyICE9ICIiKQ0KDQp0b2tlbiA8LSBnZXRfdG9rZW4oKQ0KdG9rZW4NCg0KYWxsZV90d2VldHMgPC0gbGlzdCgpDQp1c2VySWRMaXN0ID0gbGlzdChUd2l0dGVyX2FjY291bnRzJFNNX1R3aXR0ZXJfdXNlcikNCnJsIDwtIHJhdGVfbGltaXQodG9rZW4sICJzdGF0dXNlcy91c2VyX3RpbWVsaW5lIikNCmZvcih1c2VyIGluIHVzZXJJZExpc3RbWzFdXSl7DQogIGFsbGVfdHdlZXRzW1t1c2VyXV0gPC0gZ2V0X3RpbWVsaW5lKHVzZXIsIG4gPSAyLCBjaGVjayA9IEYpDQogIHByaW50KCJyYXRlIGxpbWl0IHJlbWFpbmluZzoiLCBzdHIocmwkcmVtYWluaW5nKSkNCiAgcHJpbnQoImF0IHVzZXI6Iiwgc3RyKHVzZXIpKQ0KICBybCA8LSBybCAlPiUNCiAgICBtdXRhdGUocmVtYWluaW5nID0gcmVtYWluaW5nIC0gMSkNCiAgIyBpZiByYXRlIGxpbWl0IGV4aGF1c3RlZCwgdGhlbiB3YWl0IHRvIHJhdGUgbGltaXQgcmVzZXQNCiAgaWYgKHJsJHJlbWFpbmluZyA9PSA1TCkgew0KICAgIHJsIDwtIHJhdGVfbGltaXQodG9rZW4sICJzdGF0dXNlcy91c2VyX3RpbWVsaW5lIikNCiAgICBwcmludCgicmF0ZSBsaW1pdCBleGNlZWRlZCwgd2FpdGluZyBmb3IgOTAwcyBhdCB1c2VyIiwgc3RyKHVzZXIpKQ0KICAgIFN5cy5zbGVlcChhcy5udW1lcmljKHJsJHJlc2V0LCAic2VjcyIpKQ0KICB9DQp9DQoNCiMjIyBOYWNoIHJlbGV2YW50ZW4gSGFzaHRhZ3MgZmlsdGVybiANCg0KKiAiYWxsZV90d2VldHMucmRzIiBpc3QgZGllIERhdGVpIG1pdCBhbGxlbiBnZXpvZ2VuZW4gVHdlZXRzLg0KKiBuYWNoIHJlbGV2YW50ZW4gVHdlZXRzIGZpbHRlcm4gbWl0IHZvcmhlciBiZXN0aW1tdGVuIEhhc2h0YWdzICgiVHdpdHRlci1IYXNodGFncy54bHN4IiksIFR3ZWV0cyBpbiBLbGVpbnNjaHJlaWJ1bmcgZm9ybWF0aWVyZW4gdW5kIGFscyAiZmluYWxfdHdlZXRzLnJkcyIgZXhwb3J0aWVyZW4uIA0KYGBge3J9DQphbGxlX3R3ZWV0cyA8LSByZWFkX3JkcygiRGF0YS9hbGxlX3R3ZWV0cy5yZHMiKQ0KDQpzdWNoYmVncmlmZmUgPC0gcmVhZF9leGNlbCgiRGF0YS9Ud2l0dGVyLUhhc2h0YWdzLnhsc3giLCBzaGVldCA9IlRhYmVsbGUyIikNCg0Kc3VjaGJlZ3JpZmZlX3ZlY3RvciA8LSBzdWNoYmVncmlmZmUkSGFzaHRhZ3MNCg0KYWxsZV90d2VldHMgPC0gYmluZF9yb3dzKGFsbGVfdHdlZXRzKQ0KDQphbGxlX3R3ZWV0cyA8LSBhbGxlX3R3ZWV0cyAlPiUgDQogIG11dGF0ZSh0ZXh0ID0gdG9sb3dlcih0ZXh0KSkNCg0KZmlsdGVydF90d2VldHMgPC0gYWxsZV90d2VldHMgJT4lIA0KICBmaWx0ZXIoc3RyX2RldGVjdCh0ZXh0LCBwYXN0ZSAoc3VjaGJlZ3JpZmZlX3ZlY3RvciwgY29sbGFwc2UgPSAifCIpKSkNCg0Kd3JpdGVfcmRzKGZpbHRlcnRfdHdlZXRzLCAiZmluYWxfdHdlZXRzLnJkcyIpDQpgYGANCg0KIyBTZW50aW1lbnRhbmFseXNlDQoNCiogbmFjaCBkZW4gImdyb8OfZW4iIFBhcnRlaWVuIGZpbHRlcm4NCiogYWxsZSBQb2xpdGlrZXIqaW5uZW4gZW50ZmVybmVuLCB3ZWxjaGUga2VpbmVuIFR3aXR0ZXJhY2NvdW50IGJlc2l0emVuDQoqIFVzZXJuYW1lcyBpbiBLbGVpbnNjaHJlaWJ1bmcgZm9ybWF0aWVyZW4NCmBgYHtyfQ0KUGFybGFtZW50YXJpZXJfc2VudGkgPC0gUGFybGFtZW50YXJpZXIgJT4lIA0KICBmaWx0ZXIoUGFydGVpIT0iQklXIikgJT4lIA0KICBmaWx0ZXIoUGFydGVpIT0iU1NXIikgJT4lIA0KICBmaWx0ZXIoUGFydGVpIT0iQlZCL0ZXIikgJT4lIA0KICBmaWx0ZXIoUGFydGVpIT0iRlciKSAlPiUgDQogIGZpbHRlcihQYXJ0ZWkhPSJmcmFrdGlvbnNsb3MiKSAlPiUgDQogIGZpbHRlcihTTV9Ud2l0dGVyX3VzZXIgIT0gIiIpICU+JSANCiAgc2VsZWN0KE5hbWUsIFBhcnRlaSwgU01fVHdpdHRlcl91c2VyLCBHZXNjaGxlY2h0KSAlPiUgDQogIG11dGF0ZShTTV9Ud2l0dGVyX3VzZXI9dG9sb3dlcihTTV9Ud2l0dGVyX3VzZXIpKQ0KYGBgDQoNCiogQ0RVICYgQ1NVIHNvd2llIEZEUCAmIERWUCB6dXNhbW1lbmbDvGdlbiANCmBgYHtyfQ0KUGFybGFtZW50YXJpZXJfc2VudGkkUGFydGVpW1BhcmxhbWVudGFyaWVyX3NlbnRpJFBhcnRlaSA9PSAiQ1NVIl0gPC0gIkNEVS9DU1UiDQpQYXJsYW1lbnRhcmllcl9zZW50aSRQYXJ0ZWlbUGFybGFtZW50YXJpZXJfc2VudGkkUGFydGVpID09ICJDRFUiXSA8LSAiQ0RVL0NTVSINClBhcmxhbWVudGFyaWVyX3NlbnRpJFBhcnRlaVtQYXJsYW1lbnRhcmllcl9zZW50aSRQYXJ0ZWkgPT0gIkZEUC9EVlAiXSA8LSAiRkRQIiANCmBgYA0KDQoqIFNlbnRpV1MgaW1wb3J0aWVyZW4sIHVtIHBvc2l0aXZlIHVuZCBuZWdhdGl2ZSBXw7ZydGVyIHp1IGtsYXNzaWZpemllcmVuDQoqIExpc3RlIHp1ciBTZW50aW1lbnRhbmFseXNlIGlzdCB2b24gVW5pdmVyc2l0w6R0IExlaXB6aWc6ICJodHRwczovL3dvcnRzY2hhdHoudW5pLWxlaXB6aWcuZGUvZGUvZG93bmxvYWQiDQpgYGB7cn0NCmxvYWQoIkRhdGEvc2VudGlXUy5SRGF0YSIpDQpzZW50aXdzIDwtIGRpY3Rpb25hcnkobGlzdChwb3NpdGl2ZT1wb3NpdGl2ZSwgbmVnYXRpdmU9bmVnYXRpdmUpKQ0KYGBgDQoNCiogQ29ycHVzIGF1cyBkZW4gVGV4dGVuIGRlciBnZWZpbHRlcnRlbiBUd2VldHMgYmlsZGVuDQpgYGB7cn0NCnR3ZWV0X2NvcnB1cyA8LSBjb3JwdXMoZmlsdGVydF90d2VldHMsIHRleHRfZmllbGQgPSAidGV4dCIpDQpgYGANCg0KKiB0b2tlbmlzaWVyZW4gZGVyIFRleHRlIHVuZCBiaWxkZW4gZWluZXIgREZNDQoqIHNlbnRpd3MgdW5kICJUd2VldC1Ub2tlbnMiIHp1c2FtbWVuZsO8aHJlbiwgc293aWUgbmFjaCBzY3JlZW5fbmFtZSBncnVwcGllcmVuDQoNCmBgYHtyfQ0KdG9rZW4gPC0gdG9rZW5zKHR3ZWV0X2NvcnB1cykNCmRmbSA8LSBkZm0odG9rZW4pDQoNCnNlbnRpIDwtIGRmbV9sb29rdXAoZGZtLCBzZW50aXdzKSAgDQpzZW50aSA8LSBkZm1fZ3JvdXAoc2VudGksIGdyb3VwcyA9IHNjcmVlbl9uYW1lKQ0KYGBgDQoNCiogREZNIHp1bSBEYXRhZnJhbWUga29udmVydGllcmVuDQoqIGRvY19pZCBpbiBLbGVpbnNjaHJlaWJ1bmcgZm9ybWF0aWVyZW4NCiogUGFybGFtZW50YXJpZXJfc2VudGkgam9pbmVuDQoqIEdydXBwaWVyZW4gbmFjaCBQYXJ0ZWkNCiogU2VudGltZW50IGRlciBlaW56ZWxuZW4gVXNlcippbm5lbiBhdWYgUGFydGVpZWJlbmUgenVzYW1tZW5mYXNzZW4gdW5kIFZlcmjDpGx0bmlzIHBvc2l0aXZlL25lZ2F0aXZlIGJpbGRlbg0KYGBge3J9DQpzZW50aV9mcmFtZSA8LSBzZW50aSAlPiUgDQogIGNvbnZlcnQodG89ICJkYXRhLmZyYW1lIikgJT4lIA0KICBhc190aWJibGUoKSAlPiUgDQogIG11dGF0ZShkb2NfaWQ9dG9sb3dlcihkb2NfaWQpKQ0KDQpzZW50aV9maW5hbF9mcmFtZSA8LSBzZW50aV9mcmFtZSAlPiUgDQogIGZ1bGxfam9pbihQYXJsYW1lbnRhcmllcl9zZW50aSwgYnk9YygiZG9jX2lkIj0iU01fVHdpdHRlcl91c2VyIikpICU+JSANCiAgZ3JvdXBfYnkoUGFydGVpKSAlPiUgDQogIHN1bW1hcmlzZShhY3Jvc3MoYyhuZWdhdGl2ZSwgcG9zaXRpdmUpLCB+cm91bmQoc3VtKC4sIG5hLnJtID0gVFJVRSkvc3VtKG5lZ2F0aXZlICsgcG9zaXRpdmUsIG5hLnJtID0gVFJVRSApLCBkaWdpdHMgPSAyKSkpDQpgYGANCg0KIyMjIEJhcmNoYXJ0DQoNCiogUGFydGVpIGFic3RlaWdlbmQgbmFjaCBuZWdhdGl2ZW0gU2VudGltZW50IHNvcnRpZXJlbg0KKiBCZXNjaHJpZnR1bmcgZGVyIFgtIHVuZCBZIFdlcnRlIMOkbmRlcm4NCiogQmFyY2hhcnQgYmlsZGVuIHVuZCBpbiBnZ3Bsb3RseSBrb252ZXJ0aWVyZW4NCmBgYHtyfQ0Kc2VudGlfYmFyIDwtIHNlbnRpX2ZpbmFsX2ZyYW1lICU+JSANCiAgbXV0YXRlKFBhcnRlaSA9IGZjdF9yZW9yZGVyKFBhcnRlaSwgcG9zaXRpdmUsIG1heCkpICU+JSANCiAgcGl2b3RfbG9uZ2VyKGMocG9zaXRpdmUsIG5lZ2F0aXZlKSwgdmFsdWVzX3RvID0gYygiVmVyaMOkbHRuaXMiKSwgbmFtZXNfdG8gPSBjKCLDhHXDn2VydW5nIikpICU+JSANCiAgZ2dwbG90KCkgKyANCiAgZ2VvbV9iYXIoYWVzKFBhcnRlaSwNCiAgICAgICAgICAgICAgIFZlcmjDpGx0bmlzLCAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgZmlsbCA9IMOEdcOfZXJ1bmcpLA0KICAgICAgICAgICBwb3NpdGlvbiA9ICJzdGFjayIsDQogICAgICAgICAgIHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNmNDY2NjYiLCAiIzhFQzlCQiIpKSArIA0KICB0aGVtZV9jbGFzc2ljKCkgKyANCiAgbGFicygNCiAgICB0aXRsZSA9ICLDhHXDn2VydW5nZW4gZGVyIFBvbGl0aWtlcippbm5lbiBhdWYgVHdpdHRlciB6dW0gVGhlbWEgJ0dlbmRlciciLA0KICAgIHN1YnRpdGxlID0gIkVpbnNjaMOkdHp1bmcgZHVyY2ggU2VudGltZW50YW5hbHlzZSIsDQogICAgeCA9ICJQYXJ0ZWkiLA0KICAgIHkgPSAiVmVyaMOkbHRuaXMiLA0KICAgIGZpbGwgPSAiw4R1w59lcnVuZyINCiAgKQ0KDQpmaW5hbF9zZW50aV9wbG90IDwtIGdncGxvdGx5KHNlbnRpX2JhcikNCmZpbmFsX3NlbnRpX3Bsb3QNCmBgYA0KDQojIFR3aXR0ZXIgTmV0endlcmsgDQoNCiogZmlsdGVydF90d2VldHMgInZlcmtsZWluZXJuIiB1bmQgaW4gdHdlZXRzX25ldHdvcmsgc3BlaWNoZXJuDQoqIHNjcmVlbl9uYW1lIGluIEtsZWluc2NocmVpYnVuZyBmb3JtYXRpZXJlbg0KYGBge3J9DQp0d2VldHNfbmV0d29yayA8LSBmaWx0ZXJ0X3R3ZWV0cyAlPiUgDQogIHNlbGVjdChzY3JlZW5fbmFtZSwNCiAgICAgICAgIHJldHdlZXRfc2NyZWVuX25hbWUsDQogICAgICAgICBjcmVhdGVkX2F0KSAlPiUgDQogIG11dGF0ZShzY3JlZW5fbmFtZSA9IHRvbG93ZXIoc2NyZWVuX25hbWUpKQ0KYGBgDQoNCiogUGFybGFtZW50YXJpZXIgRGF0YWZyYW1lIG1pdCB0d2VldHNfbmV0d29yayBqb2luZW4sIHVtIEtsYXJhbWVuIHVuZCBQYXJ0ZWl6dWdlaMO2cmlna2VpdCBkZXIgUG9saXRpa2VyKmlubm5lbiB6dSBiZWtvbW1lbg0KYGBge3J9DQpwYXJsYW1lbnRhcmllcl9uZXR3b3JrIDwtIFBhcmxhbWVudGFyaWVyICU+JSANCiAgc2VsZWN0KE5hbWUsDQogICAgICAgICBQYXJ0ZWksDQogICAgICAgICBTTV9Ud2l0dGVyX3VzZXIpICU+JSANCiAgZHJvcF9uYShTTV9Ud2l0dGVyX3VzZXIpICU+JSANCiAgbXV0YXRlKFNNX1R3aXR0ZXJfdXNlciA9IHRvbG93ZXIoU01fVHdpdHRlcl91c2VyKSkgJT4lIA0KICByZW5hbWUoInNjcmVlbl9uYW1lIiA9ICJTTV9Ud2l0dGVyX3VzZXIiKQ0KDQpuZXR3b3JrX2RhdGEgPC0gcGFybGFtZW50YXJpZXJfbmV0d29yayAlPiUgDQogIGxlZnRfam9pbih0d2VldHNfbmV0d29yaywgYnkgPSAic2NyZWVuX25hbWUiKQ0KYGBgDQoNCiogSMOkdWZpZ2tlaXQgZGVyIFR3ZWV0cyB6dW0gVGhlbWEgYmVyZWNobmVuIA0KKiBIw6R1Zmlna2VpdCB6dSBuZXR3b3JrX2RhdGEgam9pbmVuDQpgYGB7cn0NCmhhdWVmaWdrZWl0X3R3ZWV0cyA8LSBuZXR3b3JrX2RhdGEgJT4lIA0KICBjb3VudChzY3JlZW5fbmFtZSkNCg0KbmV0d29ya19kYXRhIDwtIG5ldHdvcmtfZGF0YSAlPiUgDQogIGxlZnRfam9pbihoYXVlZmlna2VpdF90d2VldHMsIGJ5ID0gInNjcmVlbl9uYW1lIikNCmBgYA0KDQoqIFZla3RvciBkZXIgc2NyZWVuX25hbWVzIGFsbGVyIFBvbGl0aWtlcippbm5lbiBlcnN0ZWxsZW4NCiogcmV0d2VldF9zY3JlZW5fbmFtZSBhdWYgZGllc2Ugc2NyZWVuX25hbWVzIGZpbHRlcm4sIHVtICJGcmVtZHVzZXIqaW5uZW4iIGF1c3p1c2NobGllw59lbiANCmBgYHtyfQ0Kc2NyZWVuX3N1Y2hlIDwtIHBhcmxhbWVudGFyaWVyX25ldHdvcmskc2NyZWVuX25hbWUNCg0KZmlsdGVyZWRfcmV0d2VldGVycyA8LSBuZXR3b3JrX2RhdGEgJT4lIA0KICBmaWx0ZXIoc3RyX2RldGVjdChyZXR3ZWV0X3NjcmVlbl9uYW1lLCBwYXN0ZSAoc2NyZWVuX3N1Y2hlLCBjb2xsYXBzZSA9ICJ8IikpKQ0KYGBgDQoNCiogTmV0eiBtaXQgcmVsZXZhbnRlbiBXZXJ0ZW4gZGVmaW5pZXJlbiBtaXQ6IA0KKiBFZGdlcyA9IHZvbiBzY3JlZW5fbmFtZSB6dSByZXR3ZWV0X3NjcmVlbl9uYW1lDQoqIE5vZGVzID0gUG9saXRpa2VyKmlubmVuIChzY3JlZW5fbmFtZSB1bmQgcmV0d2VldF9zY3JlZW5fbmFtZSkgDQoqIEpvaW5lIGF1ZnMgTmV0eiBQYXJ0ZWl6dWdlaMO2cmlna2VpdCwgS2xhcm5hbWVuIHVuZCBIw6R1Zmlna2VpdCBkZXIgVHdlZXRzIHp1bSBUaGVtYSAobikNCmBgYHtyfQ0KbmV0eiA8LSBmaWx0ZXJlZF9yZXR3ZWV0ZXJzICU+JSANCiAgZmlsdGVyKCFpcy5uYShyZXR3ZWV0X3NjcmVlbl9uYW1lKSkgJT4lIA0KICBzZWxlY3QoZnJvbSA9IHNjcmVlbl9uYW1lLCB0byA9IHJldHdlZXRfc2NyZWVuX25hbWUpICU+JSANCiAgYXNfdGJsX2dyYXBoDQoNCm5ldHogPC0gbmV0eiAlPiUgDQogIG11dGF0ZSgNCiAgICBkZWdyZWUgPSBjZW50cmFsaXR5X2RlZ3JlZShtb2RlID0gImluIiksIA0KICAgIGNvbXBvbmVudCA9IGdyb3VwX2NvbXBvbmVudHMoKQ0KICApICU+JSANCiAgbGVmdF9qb2luKG5ldHdvcmtfZGF0YSAlPiUgDQogICAgICAgICAgICAgIHNlbGVjdChOYW1lLCBzY3JlZW5fbmFtZSwgUGFydGVpLCBuKSAlPiUgZGlzdGluY3Qoc2NyZWVuX25hbWUsIC5rZWVwX2FsbCA9IFQpLA0KICAgICAgICAgICAgYnkgPSBjKCAibmFtZSIgPSJzY3JlZW5fbmFtZSIpKSANCmBgYA0KDQoqIEZhcmJlbiBmw7xyIFBhcnRlaWVuIGRlZmluaWVyZW4NCmBgYHtyfQ0KcGFydGVpX2ZhcmJlbiA8LSBsaXN0KA0KICAiQ0RVL0NTVSIgPSAiYmxhY2siLA0KICAiU1BEIiA9ICJyZWQiLA0KICAiQ1NVIiA9ICJibGFjayIsDQogICJGRFAiID0gIiNlMmIwMDciLA0KICAiR1LDnE5FIiA9ICIjMDdDMjNGIiwNCiAgIkxJTktFIiA9ICIjZGU0YzhhIiwgDQogICJBZkQiID0gImJsdWUiDQopDQpgYGANCg0KIyBOZXR6d2Vyaw0KDQpadXdlaXN1bmcgdm9uIEF0dHJpYnV0ZW4gYW4gTm9kZXM6DQoqIFBhcnRlaXp1Z2Vow7ZyaWdrZWl0IGluIEZhcmJlDQoqIEtsYXJuYW1lIGRlciBQb2xpdGlrZXIqaW5uZW4gYWxzIExhYmVsIA0KKiBBbnphaGwgZGVyIFR3ZWV0cyBpbiBHcsO2w59lDQpgYGB7cn0NCm5ldHpfcGxvdCA8LSBuZXR6ICU+JSANCiAgZmlsdGVyKGNvbXBvbmVudCA8PSA2KSAlPiUgDQogIG11dGF0ZShkZWdyZWUgPSBjZW50cmFsaXR5X2RlZ3JlZShtb2RlID0gImluIikpICU+JSANCiAgZ2dyYXBoKGxheW91dCA9ICJmciIpICsNCiAgZ2VvbV9lZGdlX2xpbmsoYWxwaGEgPSAwLjI1LCBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoIjUiLCAibW0iKSkpICsNCiAgZ2VvbV9ub2RlX3BvaW50KGFlcyhzaXplID0gbiwgY29sb3IgPSBQYXJ0ZWkpKSArIA0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFydGVpX2ZhcmJlbikgKw0KICB0aGVtZV9ncmFwaChiYWNrZ3JvdW5kID0gIndoaXRlIikgKyAjIHRoZW1lDQogIGdlb21fbm9kZV9sYWJlbChhZXMoZmlsdGVyID0gbiA+PSAxNSwgbGFiZWwgPSBOYW1lKSwgcmVwZWwgPSBULCBzaG93LmxlZ2VuZCA9IEYsIGFscGhhID0gMC41KSArICNwb3NpdGlvbiA9ICJqaXR0ZXIiDQogIGxhYnModGl0bGUgPSAiUmV0d2VldC1OZXR6d2Vya2UgZGV1dHNjaGVyIFBvbGl0aWtlcippbm5lbiIsIHNpemUgPSAiQW56YWhsIFR3ZWV0cyIsIHN1YnRpdGxlID0gInp1bSBUaGVtYSAnR2VuZGVyJyBhYiAyMDE2IikNCmBgYA0KYGBge3J9DQpuZXR6X3Bsb3QgDQpgYGANCg0KTk9ERVMgREVVVExJQ0hFUkUgQUJTVFVGVU5HLCBWTFQuIFRIRU1FIEZVTktUSU9OSUVSVCBOSUNIVCBSSUNIVElHDQoNCg0K